﻿#include "cyclone_type_visitor.h"

namespace cyclone::parser
{

    Json CycloneTypeVisitor::visit(FormalParser::PrimitiveTypeContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        return JsonVisitorHelper::jsonifyTypeNode(ctx);
    }

    Json CycloneTypeVisitor::visit(FormalParser::CommaGenericContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        std::vector<FormalParser::GenericKindContext *> list = {ctx->t0};
        return visitGenericContext(list, ctx->internalType);
    }

    Json CycloneTypeVisitor::visit(FormalParser::AngleGenericContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        std::vector<FormalParser::GenericKindContext *> list = {ctx->genericKind()};
        return visitGenericContext(list, ctx->internalType);
    }

    Json CycloneTypeVisitor::visit(FormalParser::TupleTypeContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        auto jsonifyNode = JsonVisitorHelper::jsonifyTypeNode(ctx);
        auto elements = Json::array();
        if (ctx->elements)
            for (const auto &e : ctx->elements->type_())
                elements.push_back(dispatch(e));
        jsonifyNode["unionElements"] = elements;
        return jsonifyNode;
    }

    Json CycloneTypeVisitor::visit(FormalParser::UnionTypeContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        auto jsonifyNode = JsonVisitorHelper::jsonifyTypeNode(ctx);
        auto elements = Json::array();
        for (const auto &e : ctx->type_())
            elements.push_back(dispatch(e));
        jsonifyNode["unionElements"] = elements;
        return jsonifyNode;
    }

    Json CycloneTypeVisitor::visit(FormalParser::StructContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        auto jsonifyNode = JsonVisitorHelper::jsonifyTypeNode(ctx);
        jsonifyNode["structFields"] = ctx->properties ? dispatch(ctx->properties) : Json::object();
        return jsonifyNode;
    }

    Json CycloneTypeVisitor::visit(FormalParser::AnonymousObjectPropertyListContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        auto jsonifyNode = Json::object();
        for (const auto &property : ctx->objectPropertyPair())
            jsonifyNode[property->key->getText()] = dispatch(property->value);
        return jsonifyNode;
    }

    Json CycloneTypeVisitor::visit(FormalParser::TypeReferenceContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        return Type{ctx->getText()};
    }

    Json CycloneTypeVisitor::visit(FormalParser::ParenthesizedPrimTypeContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        return ctx->internalType ? dispatch(ctx->internalType) : defaultResult();
    }

    Json CycloneTypeVisitor::visit(FormalParser::QualifiedNameContext *ctx)
    {
        IF_NULLPTR_RETURN_DEFAULT(ctx);
        return Type{ctx->getText()};
    }
    static Json& formatNestedGeneric(Json &current, std::vector<FormalParser::GenericKindContext *> &list)
    {
        if (list.size())
        {
            current["typeId"] = list[0]->getText();
            current["internalType"] = Json::object();
            list.erase(list.begin());
            if (list.size())
                return formatNestedGeneric(current["internalType"], list);
        }
        return current;
    }
    Json CycloneTypeVisitor::visitGenericContext(std::vector<FormalParser::GenericKindContext *> &list, FormalParser::Type_Context *internal)
    {
        auto genericTypeAnnotation = Json::object();
        auto &nested = formatNestedGeneric(genericTypeAnnotation, list);
        if (internal)
            nested["internalType"] = dispatch(internal);
        return genericTypeAnnotation;
    }
}
